package com.gitee.ywj1352.ds.aop;


import com.gitee.ywj1352.ds.aop.annoatation.MyHysitry;
import com.gitee.ywj1352.ds.aop.annoatation.SemaphoreBreaker;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.util.concurrent.*;

@Aspect
@Component
@SuppressWarnings("all")
public class ServerControllerAspect {

    private final ExecutorService es = Executors.newSingleThreadExecutor();

    private Semaphore semaphore = null;

    @Pointcut("@annotation(com.gitee.ywj1352.ds.aop.annoatation.MyHysitry)")
    public void getPoint(){
    }

    @Pointcut("@annotation(com.gitee.ywj1352.ds.aop.annoatation.SemaphoreBreaker)")
    public void getPointSemaphoreBreaker(){
    }

    // 在写aop的时候一定要加上  point 和 annotation
    @Around(value = "getPoint() && @annotation(myHysitry)")
    public Object doAround(ProceedingJoinPoint pjp,MyHysitry myHysitry) throws Throwable {
        String  msg = (String)pjp.getArgs()[0];
        Future<Object> submit = es.submit(() -> {
            Object object = null;
            try {
                object = pjp.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return object;
        });
        Object returnValue = null;
        try {
            returnValue = submit.get(150, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
            throw e;
        } catch (TimeoutException e) {
            //取消处理
            submit.cancel(true);
            return  errorMessage(msg);
        }
        return returnValue;
    }

    @Around(value = "getPointSemaphoreBreaker() && @annotation(semaphoreBreaker)")
    public Object doAroundSemaphoreBreaker(ProceedingJoinPoint pjp, SemaphoreBreaker semaphoreBreaker) throws Throwable {
        String  msg = (String)pjp.getArgs()[0];
        if (semaphore == null){
            int value = semaphoreBreaker.value();
            /**
             * 信号量在这里的作用是:
             * 设置3个信号量
             * 当3个线程进入,都在处理业务还没有返回值 并且没有 release 的时候
             * 第四个 线程 tryAcquire 时候拿不到返回 false
             */
            semaphore = new Semaphore(value);
        }
        Object returnValue = null;
        try {
            if (semaphore.tryAcquire()){
                //限流 value 个并发量
                returnValue = pjp.proceed();
            }else{
                // 超过限流
                return errorMessage(msg);
            }
        }finally {
            semaphore.release();
        }
        return returnValue;
    }


    public String errorMessage(String msg){
        return "uuu" + msg;
    }
    @PreDestroy
    public void preDestroy(){
        es.shutdown();
    }

}
